home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
- #
- # Copyright (c) 2003 Linuxant inc.
- #
- # NOTE: The use and distribution of this software is governed by the terms in
- # the file LICENSE, which is included in the package. You must read this and
- # agree to these terms before using or distributing this software.
- #
- # This script is called as a usermodehelper to start and stop the
- # DCP (Digital Call Progress) audio monitoring playback process for
- # the Conexant HSF softmodem driver under Linux.
- #
- # It tries to be as system and distribution-neutral as possible.
-
- $CNXTDCPDEVICE=$ENV{'CNXTDCPDEVICE'};
- if ($CNXTDCPDEVICE eq "") {
- $CNXTDCPDEVICE=0;
- }
-
- $piddir="/var/run";
- $pidfile="$piddir/hsfdcpd$CNXTDCPDEVICE.pid";
-
- $CNXTDCPACTION=$ENV{'CNXTDCPACTION'};
- if ($CNXTDCPACTION) {
- open STDOUT, ">/var/run/hsfdcpd$CNXTDCPDEVICE.out";
- open STDERR, ">/var/run/hsfdcpd$CNXTDCPDEVICE.err";
- open STDIN, "</dev/null";
- }
-
- if ($CNXTDCPACTION eq "start") {
- if($pid=fork) {
- # parent
- exit 0;
- } elsif (defined $pid) {
- # child continues
- $inchild=1;
- open PIDFILE, ">$pidfile" or die "$0: can't create $pidfile: $!\n";
- print PIDFILE "$$\n";
- close PIDFILE;
- } else {
- die "$0: fork failed: $!\n";
- }
-
- } elsif ($CNXTDCPACTION eq "stop") {
- open PIDFILE, "<$pidfile" or die "$0: can't open $pidfile: $!\n";
- $pid=<PIDFILE>;
- chop $pid;
- close PIDFILE;
- if ($pid > 0) {
- kill 'TERM', $pid; # or die "$0: kill $pid failed: $!\n";
- }
- exit 0;
- } elsif ($CNXTDCPACTION eq "") {
- } else {
- die "$0: invalid CNXTDCPACTION\n";
- }
-
- END {
- if ($inchild) {
- unlink $pidfile;
- }
- }
-
- $SIG{TERM} = sub { exit; }; # execute END block
- $SIG{INT} = sub { exit; }; # execute END block
- $SIG{PIPE} = sub { };
-
- use Errno;
- use Fcntl;
-
- $dcpdev="/dev/hsfdcp$CNXTDCPDEVICE";
-
- sysopen DCPDEV, "$dcpdev", (O_RDONLY | O_NDELAY | O_NONBLOCK) or die "$0: can't open $dcpdev";
-
- $CNXTDCPRATE=$ENV{'CNXTDCPRATE'};
- if ($CNXTDCPRATE eq "") {
- $CNXTDCPRATE=16000;
- }
-
- $blocksize=2048;
-
- $AFMT_S16_LE=0x10;
- $AFMT_S16_BE=0x20;
- $SNDCTL_DSP_RESET=0x5000;
- $SNDCTL_DSP_STEREO=0xc0045003;
- $SNDCTL_DSP_CHANNELS=0xc0045006;
- $SNDCTL_DSP_SETFMT=0xc0045005;
- $SNDCTL_DSP_SPEED=0xc0045002;
- $SNDCTL_DSP_SETFRAGMENT=0xc004500a;
-
- $snddev = "/dev/dsp";
-
- $sndfrag = (0x7fff << 16) | (log($blocksize)/log(2));
-
- $sndstereo = 0;
-
- $sndchan = 1;
-
- $sndfmt = $AFMT_S16_LE;
-
- $sndspeed = $CNXTDCPRATE;
-
- $rin = $win = $ein = "";
- vec($rin, fileno(DCPDEV), 1) = 1;
- $ein = $rin | $win;
-
- # start with two-block buffer to prevent underruns
- $buffersize=2*$blocksize;
-
- $buf = pack("a$buffersize", "");
-
- $timeout=undef;
-
- $len=0;
- $buflen=$buffersize;
-
- while(1) {
-
- ($nfound, $timeleft) = select($rout=$rin, $wout=$win, $eout=$ein, $timeout);
-
- if ($nfound > 0) {
- if($rout eq $rin) {
- $r = sysread DCPDEV, $buf, $buflen - $len, $len;
- if ($r <= 0) {
- die "$0: read from $dcpdev: $!\n";
- } else {
- $len += $r;
- }
- if ($len == $buflen) {
- if((!defined(fileno(DSPDEV))) && (!defined(fileno(RECORD)))) {
-
- if (! -e "/etc/hsfmodem/nodcpaudio") {
- $sndfragarg = pack("L", $sndfrag);
- $sndstereoarg = pack("L", $sndstereo);
- $sndchanarg = pack("L", $sndchan);
- $sndfmtarg = pack("L", $sndfmt);
- $sndspeedarg = pack("L", $sndspeed);
-
- if (!((sysopen DSPDEV, "$snddev", (O_WRONLY | O_NDELAY | O_NONBLOCK)) &&
- ioctl(DSPDEV, $SNDCTL_DSP_RESET, 0) &&
- ioctl(DSPDEV, $SNDCTL_DSP_SETFRAGMENT, $sndfragarg) &&
- ioctl(DSPDEV, $SNDCTL_DSP_STEREO, $sndstereoarg) &&
- ioctl(DSPDEV, $SNDCTL_DSP_CHANNELS, $sndchanarg) &&
- ioctl(DSPDEV, $SNDCTL_DSP_SETFMT, $sndfmtarg) &&
- ioctl(DSPDEV, $SNDCTL_DSP_SPEED, $sndspeedarg)
- )) {
- print STDERR "$0: can't use $snddev: $!\n";
- open DSPDEV, "|sox -t raw -r $CNXTDCPRATE -sw -c 1 - -t ossdsp $snddev" or print STDERR "$0: can't open sox pipe either: $!\n";
- $convertsamplestostereo = undef;
- } else {
- $convertsamplestostereo = unpack("L", $sndstereoarg);
- }
- }
-
- if((!defined(fileno(RECORD))) && (-d "/etc/hsfmodem/dcprecord")) {
- $cnt=0;
- while(1) {
- $recfn= sprintf "/etc/hsfmodem/dcprecord/%03d", $cnt;
- if(sysopen (RECORD, $recfn, O_WRONLY | O_CREAT | O_EXCL, 0600)) {
- last;
- }
- if ($!{EEXIST}) {
- $cnt++;
- next;
- }
- print STDERR "$0: sysopen $recfn: $!\n";
- last;
- }
- }
-
- $timeout=0.5;
- }
-
- if(defined(fileno(RECORD))) {
- $w = syswrite RECORD, $buf, $len;
- if ($w != $len) {
- print STDERR "$0: syswrite record $len returned $w ($!)\n";
- }
- }
-
- if(defined(fileno(DSPDEV))) {
- if ($convertsamplestostereo) {
- @samples=unpack("S*", $buf);
- for ($c = 0; $c < @samples; $c++) {
- $samples[$c] = $samples[$c] | ($samples[$c] << 16);
- }
- $buf = pack("L*", @samples);
- $len *= 2;
- }
- $w = syswrite DSPDEV, $buf, $len;
- if ($w != $len) {
- print STDERR "$0: syswrite $len returned $w ($!)\n";
- if ($!{EPIPE}) {
- close DSPDEV;
- }
- }
- }
-
- if((!defined(fileno(DSPDEV))) && (!defined(fileno(RECORD)))) {
- sleep 5; # delay retry
- $len=0;
- $buflen=$buffersize;
- while(sysread(DCPDEV, $buf, $buflen) > 0) {};
- next;
- }
-
- $len = 0;
- $buflen = $blocksize;
- }
- }
- if($eout eq $ein) {
- print STDERR "$0: eout\n";
- }
- } else {
- # timeout
- if(defined(fileno(DSPDEV))) {
- close DSPDEV;
- }
- if(defined(fileno(RECORD))) {
- close RECORD;
- }
- $timeout=undef;
- $len=0;
- $buflen=$buffersize;
- }
- }
-